package com.jingtai.shop.service.user.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jingtai.common.constants.CommonConstant;
import com.jingtai.common.constants.RedisConstant;
import com.jingtai.common.enums.AccountStatusEnum;
import com.jingtai.common.enums.DeleteFlagEnum;
import com.jingtai.common.enums.SmsTypeEnum;
import com.jingtai.common.template.ResultMapInfo;
import com.jingtai.common.utils.EncryptUtil;
import com.jingtai.common.utils.MyBeanUtils;
import com.jingtai.common.utils.random.TokenUtil;
import com.jingtai.common.webfacade.error.CommonException;
import com.jingtai.common.webfacade.error.ErrorEnum;
import com.jingtai.core.entity.member.MemberInfo;
import com.jingtai.core.mapper.member.MemberInfoMapper;
import com.jingtai.shop.common.config.jwt.JwtConfig;
import com.jingtai.shop.common.utils.JwtTokenUtils;
import com.jingtai.shop.common.utils.sms.SendMessageUtils;
import com.jingtai.shop.service.user.MemberInfoService;
import com.jingtai.shop.webfacade.bo.user.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author GR123
 * @since 2020-11-29
 */
@Slf4j
@Service
public class MemberInfoServiceImpl extends ServiceImpl<MemberInfoMapper, MemberInfo> implements MemberInfoService{

    @Resource
    private MemberInfoService memberInfoService;
    @Resource
    private JwtTokenUtils jwtTokenUtils;
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private JwtConfig jwtConfig;
    @Resource
    private SendMessageUtils sendMessageUtils;

    /**
     * 用户注册
     */
    @Override
    public boolean userRegister(UserRegisterBO bo) {
        MemberInfo existUserName = memberInfoService.getOne(Wrappers.lambdaQuery(MemberInfo.class).eq(MemberInfo::getUserName, bo.getUserName())
                .eq(MemberInfo::getDeleteFlag, DeleteFlagEnum.NOT_DELETE.getCode()));
        if (ObjectUtil.isNotEmpty(existUserName)) {
            throw new CommonException(ResultMapInfo.USEREXIST.getMessage());
        }

        MemberInfo existUserPhone = memberInfoService.getOne(Wrappers.lambdaQuery(MemberInfo.class).eq(MemberInfo::getPhone, bo.getPhone())
                .eq(MemberInfo::getDeleteFlag, DeleteFlagEnum.NOT_DELETE.getCode()));
        if (ObjectUtil.isNotEmpty(existUserPhone)) {
            throw new CommonException(ErrorEnum.PHONE_NUMBER_OCCUPY);
        }

        String sendCode = redisTemplate.opsForValue().get(RedisConstant.SMS_VERIFICATION_CODE_REGISTER + bo.getPhone());
        if (StringUtils.isEmpty(sendCode)){
            throw new CommonException(ErrorEnum.VERIFICATION_TIMEOUT);
        }

        if (!StringUtils.equals(sendCode,bo.getSmsCode())){
            throw new CommonException(ErrorEnum.VERIFICATION_ERROR);
        }

        MemberInfo memberInfo = MyBeanUtils.copyPropertiesChaining(bo, MemberInfo::new);
        memberInfo.setPassword(EncryptUtil.Base64Encode(memberInfo.getPassword()));
        memberInfo.setNickName(CommonConstant.DEFAULT_NICK_NAME + bo.getPhone());
        return memberInfoService.save(memberInfo);
    }

    /**
     * 用户登录
     */
    @Override
    public Map<String, String> userLogin(UserLoginBO bo) {
        MemberInfo existUserNameOrPhone = memberInfoService.getOne(Wrappers.lambdaQuery(MemberInfo.class)
                .and(wrapper -> wrapper.eq(MemberInfo::getUserName, bo.getUserName())
                        .or()
                        .eq(MemberInfo::getPhone, bo.getUserName()))
                .eq(MemberInfo::getDeleteFlag, DeleteFlagEnum.NOT_DELETE.getCode()));
        if (ObjectUtil.isEmpty(existUserNameOrPhone)) {
            throw new CommonException(ErrorEnum.NOT_INVALID_PHONE_NAME);
        }

        if (ObjectUtil.equal(AccountStatusEnum.LOGOUT.getValue(), existUserNameOrPhone.getEnableState())) {
            throw new CommonException(ResultMapInfo.USERLOGOUT.getMessage());
        }

        if (ObjectUtil.equal(AccountStatusEnum.FREEZE.getValue(), existUserNameOrPhone.getEnableState())) {
            throw new CommonException(ResultMapInfo.SHOPUSERFROZEN.getMessage());
        }

        String reducePassword = EncryptUtil.Base64Decode(existUserNameOrPhone.getPassword());
        if (!StringUtils.equals(reducePassword,bo.getPassword())) {
            throw new CommonException(ResultMapInfo.OLDPASSWORDERROR.getMessage());
        }

        //相当于把userId设置成主键-->token
        String token = jwtTokenUtils.generateToken(existUserNameOrPhone.getUserName(), existUserNameOrPhone.getId());

        redisTemplate.opsForValue().set(RedisConstant.LOGIN_USER_PRE_KEY + existUserNameOrPhone.getId(),
                jwtTokenUtils.setTokenToRedis(token),
                jwtConfig.getExpiration(), TimeUnit.HOURS);

        Map<String, String> map = new HashMap<>();
        map.put(jwtConfig.getTokenHeader(), jwtConfig.getTokenStart() + " " + token);
        return map;
    }

    /**
     * 用户登出
     */
    @Override
    public void userLogout(HttpServletRequest request) {
        Long id = jwtTokenUtils.getUserIdFromToken(request);
        redisTemplate.delete(RedisConstant.LOGIN_USER_PRE_KEY + id);
    }

    /**
     * 忘记密码
     */
    @Override
    public boolean userForgetPwd(UserForgetPwdBO bo) {
        MemberInfo existPhone = memberInfoService.getOne(Wrappers.lambdaQuery(MemberInfo.class).eq(MemberInfo::getPhone, bo.getPhone())
                .eq(MemberInfo::getDeleteFlag, DeleteFlagEnum.NOT_DELETE.getCode()));
        if (ObjectUtil.isEmpty(existPhone)){
            throw new CommonException(ErrorEnum.NOT_INVALID_PHONE);
        }

        if (ObjectUtil.equal(AccountStatusEnum.LOGOUT.getValue(), existPhone.getEnableState())) {
            throw new CommonException(ResultMapInfo.USERLOGOUT.getMessage());
        }

        if (ObjectUtil.equal(AccountStatusEnum.FREEZE.getValue(), existPhone.getEnableState())) {
            throw new CommonException(ResultMapInfo.SHOPUSERFROZEN.getMessage());
        }

        String sendCode = redisTemplate.opsForValue().get(RedisConstant.SMS_VERIFICATION_CODE_FORGETPWD + bo.getPhone());
        if (StringUtils.isEmpty(sendCode)){
            throw new CommonException(ErrorEnum.VERIFICATION_TIMEOUT);
        }

        if (!StringUtils.equals(sendCode,bo.getSmsCode())){
            throw new CommonException(ErrorEnum.VERIFICATION_ERROR);
        }

        existPhone.setPassword(EncryptUtil.Base64Encode(existPhone.getPassword()));
        return memberInfoService.updateById(existPhone);
    }

    /**
     * 用户获取验证码
     * 待完善
     */
    @Override
    public boolean userObtainCode(UserObtainCodeBO bo) {

        //生成验证码
        String code = TokenUtil.generateCode(6);
        boolean sendStatus=false;
        //注册
        if (ObjectUtil.equal(SmsTypeEnum.REGISTER.getStatus(), bo.getEstate())) {
             sendStatus = sendMessageUtils.sendMessageToRegister(bo.getPhone(), code);
        } else {
            //忘记密码
            sendStatus=sendMessageUtils.sendMessageToForgetpwd(bo.getPhone(),code);
        }

        return sendStatus;
    }

    /**
     * 用户-修改个人信息
     */
    @Override
    public boolean editUserInfo(EditUserInfoBO bo) {

        //一般情况下不轻易修改账号和手机号,因为前者涉及到全局id以及token验证
        if (StringUtils.isNotBlank(bo.getNickName()) || StringUtils.isNotBlank(bo.getPhone())
                || StringUtils.isNotBlank(bo.getPassword())) {
            redisTemplate.delete(RedisConstant.LOGIN_USER_PRE_KEY + bo.getId());
        }

        MemberInfo memberInfo = MyBeanUtils.copyPropertiesChaining(bo, MemberInfo::new);
        memberInfo.setPassword(EncryptUtil.Base64Encode(memberInfo.getPassword()));
        return memberInfoService.updateById(memberInfo);
    }

    /**
     * 用户-注销用户
     */
    @Override
    public boolean userDestroy(HttpServletRequest request) {
        Long id = jwtTokenUtils.getUserIdFromToken(request);
        redisTemplate.delete(RedisConstant.LOGIN_USER_PRE_KEY + id);

        MemberInfo memberInfo = new MemberInfo();
        memberInfo.setId(id);
        memberInfo.setEnableState(AccountStatusEnum.LOGOUT.getValue());
        memberInfo.setDeleteFlag(DeleteFlagEnum.DELETE.getCode());
        return memberInfoService.updateById(memberInfo);
    }
}
